package com.itheima.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.session.HttpSessionEventPublisher;

/**
 * @author 吴
 * @version V1.0
 * @Description  springSecurity 配置类
 * @Package com.itheima.config
 * @date 2021/11/28 11:28
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 启动注解
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Bean
    public PasswordEncoder pwd(){
        return new BCryptPasswordEncoder();
    }

    @Bean //加载中文认证提示信息
    public ReloadableResourceBundleMessageSource messageSource(){
        ReloadableResourceBundleMessageSource messageSource = new   ReloadableResourceBundleMessageSource();
        //加载org/springframework/security包下的中文提示信息 配置文件
        messageSource.setBasename("classpath:messages_zh_CN");
        return messageSource;
    }


    /**
     * 注册 SessionRegistry，该 Bean 用于管理 Session 会话并发控制
     */
    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }



    /**
     *  安全请求
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用 csrf
        http.csrf().disable();

        // 授权认证
        http.authorizeRequests()
                // 那些请求或者文件需要放行
                .antMatchers("/login.html","/css/**","/img/**","/js/**","/plugins/**","/template/**")
                .permitAll()
                .anyRequest().authenticated();

        //  让默认的iframe拒绝访问失效
        http.headers().frameOptions().disable();

        // 设置登录页面
        http.formLogin()
                .loginPage("/login.html")       // 登陆页面
                .usernameParameter("username").passwordParameter("password")  // 账号密码
                .loginProcessingUrl("/user/login")      // 登陆地址
                .defaultSuccessUrl("/pages/main.html")   // 成功后调转 默认转发请求
                .failureUrl("/login.html?error");      // 失败页面

        // 退出
        http.logout()
                .logoutUrl("/user/logout")      // 退出地址
                .logoutSuccessUrl("/login.html");   // 退出成功后跳转的地址

        // 403权限异常
//        http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

        // 单独会话 只允许该用户一个地方登录
//        http.sessionManagement()
//                .invalidSessionUrl("/login.html")
//                .maximumSessions(1)
//                .maxSessionsPreventsLogin(true)
//                .sessionRegistry(sessionRegistry());

        // 记住我
        http.rememberMe()
                .rememberMeParameter("remember-me")
                .tokenValiditySeconds(60*60*24);

    }

    /**
     * 处理用户账号密码和角色、权限
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.userDetailsService(myUserDetailsService).passwordEncoder(pwd());
    }
}
